"""
数据同步API端点
提供同步任务的CRUD操作、执行管理等RESTful接口
"""

from fastapi import APIRouter, Depends, HTTPException, status, Query, Body, BackgroundTasks
from fastapi.responses import FileResponse
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Optional, List
import os

from app.core.database import get_db
from app.core.dependencies import get_current_active_user
from app.models.auth import User
from app.models.sync import SyncType, TargetType, ExecutionStatus
from app.schemas.sync import (
    SyncTaskCreate, SyncTaskUpdate, SyncTaskResponse, SyncTaskListResponse,
    SyncExecutionResponse, SyncExecutionListResponse, SyncLogListResponse,
    SyncExecutionRequest, BatchSyncTaskRequest, BatchSyncTaskResponse
)
from app.schemas.common import BaseResponse
from app.services.sync_service import sync_service
from app.services.permission_hierarchy_service import require_resource_action
from app.core.logger import logger

router = APIRouter()


@router.get("", response_model=BaseResponse[SyncTaskListResponse])
async def get_sync_tasks(
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(10, ge=1, le=100, description="每页大小"),
    search: Optional[str] = Query(None, description="搜索关键词"),
    sync_type: Optional[SyncType] = Query(None, description="同步类型"),
    target_type: Optional[TargetType] = Query(None, description="目标类型"),
    is_active: Optional[bool] = Query(None, description="是否启用"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_task", "view"))
):
    """
    获取同步任务列表
    
    支持分页、搜索和筛选功能：
    - **page**: 页码，从1开始
    - **page_size**: 每页大小，最大100
    - **search**: 搜索关键词，支持任务名称、显示名称、描述
    - **sync_type**: 同步类型筛选
    - **target_type**: 目标类型筛选
    - **is_active**: 启用状态筛选
    """
    try:
        result = await sync_service.get_sync_tasks(
            db=db,
            page=page,
            page_size=page_size,
            search=search,
            sync_type=sync_type,
            target_type=target_type,
            is_active=is_active,
            current_user=current_user
        )
        
        return BaseResponse(
            data=result,
            message="获取同步任务列表成功",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取同步任务列表失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="获取同步任务列表失败"
        )


@router.get("/{task_id}", response_model=BaseResponse[SyncTaskResponse])
async def get_sync_task(
    task_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_task", "view"))
):
    """
    获取单个同步任务详情
    
    - **task_id**: 同步任务ID
    """
    try:
        result = await sync_service.get_sync_task(
            db=db,
            task_id=task_id,
            current_user=current_user
        )
        
        if not result:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="同步任务不存在"
            )
        
        return BaseResponse(
            data=result,
            message="获取同步任务成功",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取同步任务失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="获取同步任务失败"
        )


@router.post("", response_model=BaseResponse[SyncTaskResponse])
async def create_sync_task(
    task_data: SyncTaskCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_task", "create"))
):
    """
    创建同步任务
    
    创建新的数据同步任务，支持以下配置：
    - **基本信息**: 任务名称、显示名称、描述
    - **数据源配置**: 源数据源、表名、自定义查询
    - **目标配置**: 目标类型、目标数据源、路径
    - **同步配置**: 同步类型、增量字段、批处理大小
    - **调度配置**: 调度类型、Cron表达式
    - **字段映射**: 源字段到目标字段的映射关系
    """
    try:
        result = await sync_service.create_sync_task(
            db=db,
            task_data=task_data,
            current_user=current_user
        )
        
        return BaseResponse(
            data=result,
            message="同步任务创建成功",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"创建同步任务失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="创建同步任务失败"
        )


@router.put("/{task_id}", response_model=BaseResponse[SyncTaskResponse])
async def update_sync_task(
    task_id: int,
    task_data: SyncTaskUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_task", "update"))
):
    """
    更新同步任务

    - **task_id**: 同步任务ID
    - 其他字段为可选更新字段
    """
    try:
        result = await sync_service.update_sync_task(
            db=db,
            task_id=task_id,
            task_data=task_data,
            current_user=current_user
        )
        
        if not result:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="同步任务不存在"
            )
        
        return BaseResponse(
            data=result,
            message="同步任务更新成功",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"更新同步任务失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="更新同步任务失败"
        )


@router.delete("/{task_id}", response_model=BaseResponse[bool])
async def delete_sync_task(
    task_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_task", "delete"))
):
    """
    删除同步任务（逻辑删除）
    
    - **task_id**: 同步任务ID
    
    注意：正在运行的任务无法删除
    """
    try:
        result = await sync_service.delete_sync_task(
            db=db,
            task_id=task_id,
            current_user=current_user
        )
        
        if not result:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="同步任务不存在"
            )
        
        return BaseResponse(
            data=True,
            message="同步任务删除成功",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除同步任务失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="删除同步任务失败"
        )


@router.post("/{task_id}/execute", response_model=BaseResponse[SyncExecutionResponse])
async def execute_sync_task(
    task_id: int,
    execution_request: SyncExecutionRequest = Body(...),
    background_tasks: BackgroundTasks = BackgroundTasks(),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_task", "execute"))
):
    """
    执行同步任务
    
    - **task_id**: 同步任务ID
    - **execution_params**: 执行参数（可选）
    - **force_full_sync**: 是否强制全量同步
    
    任务将在后台异步执行，可通过执行记录API查看进度
    """
    try:
        # 设置任务ID
        execution_request.task_id = task_id
        
        result = await sync_service.execute_sync_task(
            db=db,
            request=execution_request,
            current_user=current_user
        )
        
        return BaseResponse(
            data=result,
            message="同步任务已开始执行",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"执行同步任务失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="执行同步任务失败"
        )


@router.get("/executions/list", response_model=BaseResponse[SyncExecutionListResponse])
async def get_sync_executions(
    task_id: Optional[int] = Query(None, description="任务ID筛选"),
    status: Optional[ExecutionStatus] = Query(None, description="执行状态筛选"),
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(10, ge=1, le=100, description="每页大小"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_execution", "view"))
):
    """
    获取同步执行记录列表
    
    - **task_id**: 任务ID筛选（可选）
    - **status**: 执行状态筛选（可选）
    - **page**: 页码
    - **page_size**: 每页大小
    """
    try:
        result = await sync_service.get_sync_executions(
            db=db,
            task_id=task_id,
            status=status,
            page=page,
            page_size=page_size,
            current_user=current_user
        )
        
        return BaseResponse(
            data=result,
            message="获取执行记录列表成功",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取执行记录列表失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="获取执行记录列表失败"
        )


@router.get("/executions/{execution_id}/logs", response_model=BaseResponse[SyncLogListResponse])
async def get_sync_logs(
    execution_id: int,
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(50, ge=1, le=200, description="每页大小"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_execution", "view"))
):
    """
    获取同步执行日志
    
    - **execution_id**: 执行记录ID
    - **page**: 页码
    - **page_size**: 每页大小
    """
    try:
        result = await sync_service.get_sync_logs(
            db=db,
            execution_id=execution_id,
            page=page,
            page_size=page_size,
            current_user=current_user
        )
        
        return BaseResponse(
            data=result,
            message="获取同步日志成功",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取同步日志失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="获取同步日志失败"
        )





@router.post("/batch", response_model=BaseResponse[BatchSyncTaskResponse])
async def batch_sync_tasks(
    request: BatchSyncTaskRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_task", "update"))
):
    """
    批量操作同步任务
    
    支持的操作类型：
    - **enable**: 启用任务
    - **disable**: 禁用任务
    - **delete**: 删除任务
    - **execute**: 执行任务
    """
    try:
        # 这里可以实现批量操作逻辑
        # 暂时返回模拟结果
        return BaseResponse(
            data=BatchSyncTaskResponse(
                success_count=len(request.task_ids),
                failed_count=0,
                results=[]
            ),
            message=f"批量{request.action}操作完成",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"批量操作失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="批量操作失败"
        )


@router.get("/{task_id}/download")
async def download_csv_file(
    task_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_task", "view"))
):
    """
    下载同步任务生成的CSV文件

    - **task_id**: 同步任务ID
    """
    try:
        # 获取任务信息
        task = await sync_service.get_sync_task(db, task_id, current_user)

        # 检查任务类型是否为CSV
        if task.target_type != TargetType.CSV:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="该任务不是CSV导出任务"
            )

        # 检查文件是否存在
        if not task.target_path or not os.path.exists(task.target_path):
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="CSV文件不存在，请先执行同步任务"
            )

        # 获取文件名
        filename = os.path.basename(task.target_path)

        # 返回文件下载响应
        return FileResponse(
            path=task.target_path,
            filename=filename,
            media_type='text/csv',
            headers={
                "Content-Disposition": f"attachment; filename={filename}"
            }
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"下载CSV文件失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="下载CSV文件失败"
        )


@router.post("/executions/{execution_id}/pause", response_model=BaseResponse[bool])
async def pause_sync_execution(
    execution_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_execution", "control"))
):
    """
    暂停同步执行

    - **execution_id**: 执行记录ID
    """
    try:
        result = await sync_service.pause_sync_execution(db, execution_id, current_user)

        if not result:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="执行记录不存在或无法暂停"
            )

        return BaseResponse(
            data=True,
            message="同步任务已暂停",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"暂停同步执行失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="暂停同步执行失败"
        )


@router.post("/executions/{execution_id}/cancel", response_model=BaseResponse[bool])
async def cancel_sync_execution(
    execution_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_execution", "control"))
):
    """
    取消同步执行

    - **execution_id**: 执行记录ID
    """
    try:
        result = await sync_service.cancel_sync_execution(db, execution_id, current_user)

        if not result:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="执行记录不存在或无法取消"
            )

        return BaseResponse(
            data=True,
            message="同步任务已取消",
            success=True
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"取消同步执行失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="取消同步执行失败"
        )


@router.get("/executions/{execution_id}/download")
async def download_execution_csv_file(
    execution_id: int,
    delimiter: Optional[str] = Query(None, description="CSV分隔符"),
    quote_char: Optional[str] = Query(None, description="CSV引用字符"),
    escape_char: Optional[str] = Query(None, description="CSV转义字符"),
    encoding: Optional[str] = Query(None, description="CSV文件编码"),
    escape_special_chars: Optional[bool] = Query(None, description="是否转义特殊字符"),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_resource_action("sync_execution", "view"))
):
    """
    下载指定执行记录生成的CSV文件

    - **execution_id**: 执行记录ID
    - **delimiter**: CSV分隔符（可选，默认为逗号）
    - **quote_char**: CSV引用字符（可选，默认为双引号）
    - **escape_char**: CSV转义字符（可选，默认为反斜杠）
    - **encoding**: CSV文件编码（可选，默认为UTF-8）
    - **escape_special_chars**: 是否转义特殊字符（可选，默认为True）
    """
    try:
        # 获取执行记录信息
        execution = await sync_service.get_sync_execution(db, execution_id, current_user)

        # 获取关联的任务信息
        task = await sync_service.get_sync_task(db, execution.task_id, current_user)

        # 检查任务类型是否为CSV
        if task.target_type != TargetType.CSV:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="该任务不是CSV导出任务"
            )

        # 检查执行是否成功完成
        if execution.status != ExecutionStatus.SUCCESS:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="该执行记录未成功完成，无法下载文件"
            )

        # 查找CSV文件
        # 文件名格式: {task_name}_{timestamp}.csv
        import os
        from app.core.config import settings

        # 获取CSV导出目录
        csv_dir = settings.CSV_EXPORT_PATH
        if not os.path.exists(csv_dir):
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="CSV导出目录不存在"
            )

        # 查找匹配的CSV文件
        # 由于文件名包含任务名称，我们可以通过任务名称来匹配文件
        import glob
        pattern = os.path.join(csv_dir, f"{task.name}_*.csv")
        matching_files = glob.glob(pattern)

        if not matching_files:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="未找到对应的CSV文件"
            )

        # 如果有多个文件，选择最新的（基于文件修改时间）
        source_file_path = max(matching_files, key=os.path.getmtime)
        filename = os.path.basename(source_file_path)

        # 如果没有指定CSV参数，直接返回原始文件
        if not any([delimiter, quote_char, escape_char, encoding, escape_special_chars is not None]):
            from fastapi.responses import FileResponse
            return FileResponse(
                path=source_file_path,
                filename=filename,
                media_type='text/csv',
                headers={
                    "Content-Disposition": f"attachment; filename={filename}"
                }
            )

        # 否则，根据参数重新格式化CSV文件
        import csv
        import tempfile
        import shutil
        from datetime import datetime
        from app.utils.timezone_utils import get_shanghai_now

        # 使用任务配置作为默认值
        csv_delimiter = delimiter or task.csv_delimiter or ','
        csv_quote_char = quote_char or task.csv_quote_char or '"'
        csv_escape_char = escape_char or task.csv_escape_char or '\\'
        csv_encoding = encoding or task.csv_encoding or 'utf-8'
        csv_escape_special = escape_special_chars if escape_special_chars is not None else True

        # 创建临时文件
        with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as temp_file:
            temp_file_path = temp_file.name

        try:
            # 读取源文件并按照新格式写入临时文件
            with open(source_file_path, 'r', newline='', encoding='utf-8') as source_file:
                reader = csv.reader(source_file)
                rows = list(reader)

                with open(temp_file_path, 'w', newline='', encoding=csv_encoding) as target_file:
                    writer = csv.writer(
                        target_file,
                        delimiter=csv_delimiter,
                        quotechar=csv_quote_char,
                        escapechar=csv_escape_char,
                        quoting=csv.QUOTE_MINIMAL
                    )

                    # 写入所有行
                    for row in rows:
                        # 如果需要处理特殊字符
                        if csv_escape_special:
                            # CSV模块会自动处理引号和特殊字符
                            writer.writerow(row)
                        else:
                            # 不处理特殊字符，直接写入
                            writer.writerow(row)

            # 生成新的文件名，包含参数信息
            timestamp = get_shanghai_now().strftime("%Y%m%d_%H%M%S")
            new_filename = f"{os.path.splitext(filename)[0]}_{timestamp}_custom.csv"

            # 返回临时文件
            from fastapi.responses import FileResponse
            return FileResponse(
                path=temp_file_path,
                filename=new_filename,
                media_type='text/csv',
                headers={
                    "Content-Disposition": f"attachment; filename={new_filename}"
                }
            )
        except Exception as e:
            # 清理临时文件
            if os.path.exists(temp_file_path):
                os.unlink(temp_file_path)
            raise e

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"下载执行记录CSV文件失败：{str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="下载CSV文件失败"
        )
